package com.gmail.volodymyrdotsenko.roo.webeasy.scaffold;

import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSISTENT_TYPE;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.logging.Logger;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.web.mvc.controller.details.DateTimeFormatDetails;
import org.springframework.roo.addon.web.mvc.controller.details.JavaTypeMetadataDetails;
import org.springframework.roo.addon.web.mvc.controller.details.WebMetadataService;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.customdata.tagkeys.MethodMetadataCustomDataKey;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MemberHoldingTypeDetails;
import org.springframework.roo.classpath.itd.AbstractItdMetadataProvider;
import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.layers.MemberTypeAdditions;
import org.springframework.roo.classpath.scanner.MemberDetails;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.support.logging.HandlerUtils;
import org.springframework.roo.support.util.CollectionUtils;

@Component
@Service
public class WebeasyScaffoldMetadataProvider extends
		AbstractItdMetadataProvider {

	private static Logger LOGGER = HandlerUtils
			.getLogger(WebeasyScaffoldMetadataProvider.class);

	@Reference
	private WebMetadataService webMetadataService;

	/**
	 * The activate method for this OSGi component, this will be called by the
	 * OSGi container upon bundle activation (result of the 'addon install'
	 * command)
	 * 
	 * @param context
	 *            the component context can be used to get access to the OSGi
	 *            container (ie find out if certain bundles are active)
	 */
	protected void activate(ComponentContext context) {

		LOGGER.info("RooWebeasyScaffold activate");

		metadataDependencyRegistry.registerDependency(
				PhysicalTypeIdentifier.getMetadataIdentiferType(),
				getProvidesType());
		addMetadataTrigger(new JavaType(RooWebeasyScaffold.class.getName()));
	}

	/**
	 * The deactivate method for this OSGi component, this will be called by the
	 * OSGi container upon bundle deactivation (result of the 'addon uninstall'
	 * command)
	 * 
	 * @param context
	 *            the component context can be used to get access to the OSGi
	 *            container (ie find out if certain bundles are active)
	 */
	protected void deactivate(ComponentContext context) {
		metadataDependencyRegistry.deregisterDependency(
				PhysicalTypeIdentifier.getMetadataIdentiferType(),
				getProvidesType());
		removeMetadataTrigger(new JavaType(RooWebeasyScaffold.class.getName()));
	}

	/**
	 * Define the unique ITD file name extension, here the resulting file name
	 * will be **_ROO_WebeasyScaffold.aj
	 */
	@Override
	public String getItdUniquenessFilenameSuffix() {
		return "WebeasyScaffold";
	}

	/**
	 * Return an instance of the Metadata offered by this add-on
	 */
	@Override
	protected ItdTypeDetailsProvidingMetadataItem getMetadata(
			String metadataIdentificationString, JavaType aspectName,
			PhysicalTypeMetadata governorPhysicalTypeMetadata,
			String itdFilename) {

		// We need to parse the annotation, which we expect to be present
		final WebeasyScaffoldAnnotationValues annotationValues = new WebeasyScaffoldAnnotationValues(
				governorPhysicalTypeMetadata);

		//LOGGER.info(annotationValues.toString());

		final JavaType formBackingType = annotationValues
				.getFormBackingObject();

		if (!annotationValues.isAnnotationFound() || formBackingType == null) {
			return null;
		}

		final MemberDetails formBackingObjectMemberDetails = getMemberDetails(formBackingType);
		if (formBackingObjectMemberDetails == null) {
			return null;
		}

		final MemberHoldingTypeDetails formBackingMemberHoldingTypeDetails = MemberFindingUtils
				.getMostConcreteMemberHoldingTypeDetailsWithTag(
						formBackingObjectMemberDetails, PERSISTENT_TYPE);
		if (formBackingMemberHoldingTypeDetails == null) {
			return null;
		}

		final Map<MethodMetadataCustomDataKey, MemberTypeAdditions> crudAdditions = webMetadataService
				.getCrudAdditions(formBackingType, metadataIdentificationString);
		if (CollectionUtils.isEmpty(crudAdditions)) {
			return null;
		}

		final FieldMetadata idField = webMetadataService
				.getIdentifierField(formBackingType);
		final SortedMap<JavaType, JavaTypeMetadataDetails> relatedApplicationTypeMetadata = webMetadataService
				.getRelatedApplicationTypeMetadata(formBackingType,
						formBackingObjectMemberDetails,
						metadataIdentificationString);
		final List<JavaTypeMetadataDetails> dependentApplicationTypeMetadata = webMetadataService
				.getDependentApplicationTypeMetadata(formBackingType,
						formBackingObjectMemberDetails,
						metadataIdentificationString);
		final Map<JavaSymbolName, DateTimeFormatDetails> datePatterns = webMetadataService
				.getDatePatterns(formBackingType,
						formBackingObjectMemberDetails,
						metadataIdentificationString);
		final Collection<JavaType> editableFieldTypes = formBackingObjectMemberDetails
				.getPersistentFieldTypes(formBackingType,
						persistenceMemberLocator);

		//LOGGER.info("try to create WebeasyScaffoldMetadata");

		return new WebeasyScaffoldMetadata(metadataIdentificationString,
				aspectName, governorPhysicalTypeMetadata, annotationValues,
				idField, relatedApplicationTypeMetadata,
				dependentApplicationTypeMetadata, datePatterns, crudAdditions,
				editableFieldTypes, typeLocationService);
	}

	@Override
	public String getProvidesType() {
		return WebeasyScaffoldMetadata.getMetadataIdentiferType();
	}

	@Override
	protected String createLocalIdentifier(JavaType javaType, LogicalPath path) {
		return WebeasyScaffoldMetadata.createIdentifier(javaType, path);
	}

	@Override
	protected String getGovernorPhysicalTypeIdentifier(
			String metadataIdentificationString) {

		JavaType javaType = WebeasyScaffoldMetadata
				.getJavaType(metadataIdentificationString);
		LogicalPath path = WebeasyScaffoldMetadata
				.getPath(metadataIdentificationString);

		return PhysicalTypeIdentifier.createIdentifier(javaType, path);
	}
}